package com.zkh.myutils.io.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zkh.myutils.utils.StringUtils;

/**
 * 文件下载，可下载文件或输入流
 * @author zkh
 */
public class FileDownload {
	//下载文件路径
	private String path="";
	//下载文件名
	private String filename;
	//下载时展示的文件名
	private String newfilename;
	//HttpServletResponse对象
	private HttpServletResponse response;
	//HttpServletRequest对象
	private HttpServletRequest request;
	//输入流
	InputStream inputStream;
	
	/**
	 * 构造器
	 * @param is 输入流
	 * @param req 请求对象
	 * @param resp 响应对象
	 */
	public FileDownload(InputStream is, HttpServletRequest req, HttpServletResponse resp){
		inputStream = is;
		request = req;
		response = resp;
	}
	
	/**
	 * 构造器
	 * @param filename 下载文件名（相对于项目根目录，可调用setPath()设置文件路径）
	 * @param req 请求对象
	 * @param resp 响应对象
	 */
	public FileDownload(String filename,HttpServletRequest req,HttpServletResponse resp) {
		this.filename = filename;
		request = req;
		response = resp;
	}
	
	/**
	 * 执行下载操作
	 */
	public void download() throws FileNotFoundException{
		//检查下载文件是否存在
		if(filename==null){
			throw new FileNotFoundException("下载文件不存在");
		}
		File file = new File(request.getSession().getServletContext().getRealPath("/") + path, filename);
		if(!file.exists()){
			throw new FileNotFoundException("下载文件不存在");
		}
		//下载文件名
		String lFilename = filename;
		//如果设置了新文件名
		if(!StringUtils.isEmpty(newfilename)){
			lFilename = newfilename + FileUtils.getSuffix(filename, true);
		};
		//设置响应头，控制浏览器下载该文件
		response.setHeader("content-disposition", "attachment;filename=" + lFilename);
		//返回文件大小
		response.setHeader("content-length", file.length()+"");
		//保存输入流
		inputStream = new FileInputStream(file);
		//读取文件
		try {
			readFile();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 执行下载流操作
	 */
	public void downloadStream() throws IOException{
		//没有文件名
		if(StringUtils.isEmpty(newfilename)) {
			throw new  RuntimeException("请设置文件名");
		}
		//设置响应头，控制浏览器下载该文件
		response.setHeader("content-disposition", "attachment;filename=" + newfilename);
		//返回文件大小
		response.setHeader("content-length", readFile()+"");
	}
	
	/**
	 * 读取流到输出流
	 * @return 流长度。下载输入流时需要计算文件大小
	 */
	private long readFile() throws IOException{
		//输入流
		try(OutputStream os = response.getOutputStream()){
			//临时变量
			int tlen;
			byte[] bytes = new byte[1024];
			//读取长度
			long len = 0;
			//将数据写入到输入流
			while((tlen=inputStream.read(bytes))>0){
				os.write(bytes, 0, tlen);len+=tlen;
			}
			//关闭流
			os.flush();
			//返回长度
			return len;
		}finally {
			inputStream.close();
		}
	}

	/**
	 * 设置文件路径，必须基于项目根目录
	 */
	public void setPath(String path) {
		this.path = path;
	}
	
	/**
	 * 设置下载时展示的文件名（不设置系统默认使用原文件名）<br /><b>
	 * 1、如果是下载文件，参数请不要带后缀，系统自动使用原文件后缀。<br />
	 * 2、如果是下载流，参数请加上后缀名。
	 * </b>
	 */
	public void setNewfilename(String newfilename) {
		this.newfilename = newfilename;
	}
}
